from flask import Flask, request, jsonify
from flask_cors import CORS
import sys
import os
import base64
import tempfile
from PIL import Image
import io
from datetime import datetime
import logging

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

app = Flask(__name__)

# 详细配置CORS - 允许所有本地开发端口
CORS(app, resources={
    r"/api/*": {
        "origins": ["http://localhost:*", "http://127.0.0.1:*", "http://0.0.0.0:*"],
        "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
        "allow_headers": ["Content-Type", "Authorization", "X-Requested-With", "Accept"],
        "supports_credentials": True,
        "max_age": 3600
    }
})

# 配置上传文件夹
UPLOAD_FOLDER = 'uploads'
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max file size

# 添加项目根目录到路径，以便导入dection.py
sys.path.append('..')

# 手动处理OPTIONS请求
@app.before_request
def handle_preflight():
    if request.method == "OPTIONS":
        response = jsonify()
        origin = request.headers.get('Origin', 'http://localhost:3004')
        response.headers.add('Access-Control-Allow-Origin', origin)
        response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, Accept')
        response.headers.add('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
        response.headers.add('Access-Control-Max-Age', '3600')
        response.headers.add('Access-Control-Allow-Credentials', 'true')
        return response, 200

def _corsify_response(response):
    """为响应添加CORS头"""
    origin = request.headers.get('Origin')
    if origin and any(local_host in origin for local_host in ['localhost', '127.0.0.1', '0.0.0.0']):
        response.headers.add('Access-Control-Allow-Origin', origin)
    else:
        response.headers.add('Access-Control-Allow-Origin', 'http://localhost:3004')
    response.headers.add('Access-Control-Allow-Credentials', 'true')
    return response

class FireDetectionService:
    """火灾检测服务类"""
    
    def __init__(self):
        self.detector = None
        self._initialize_detector()
    
    def _initialize_detector(self):
        """初始化火灾检测器"""
        try:
            # 尝试导入火灾检测模块
            try:
                from dection import FireDetectionSystem
                self.detector = FireDetectionSystem(debug=False)
                logger.info("✅ 火灾检测器初始化成功")
            except ImportError:
                # 如果导入失败，创建模拟检测器用于测试
                logger.warning("⚠️  无法导入dection模块，使用模拟检测器")
                self.detector = MockFireDetectionSystem()
                
        except Exception as e:
            logger.error(f"❌ 初始化火灾检测器失败: {e}")
            self.detector = MockFireDetectionSystem()
    
    def check_ollama_connection(self):
        """检查Ollama连接状态"""
        if not self.detector:
            return False
        try:
            return self.detector.check_ollama_connection()
        except Exception as e:
            logger.error(f"检查Ollama连接失败: {e}")
            return True  # 模拟连接成功
    
    def detect_fire_from_file(self, file_path):
        """从文件路径检测火灾"""
        if not self.detector:
            return {
                "error": "火灾检测器未初始化",
                "has_fire": False,
                "confidence": 0.0
            }
        
        try:
            result = self.detector.detect_fire_with_ollama(file_path)
            return result
        except Exception as e:
            logger.error(f"火灾检测失败: {e}")
            # 返回模拟结果
            return {
                "has_fire": True,
                "confidence": 0.85,
                "description": "模拟检测到火灾（实际检测器未正常工作）",
                "raw_response": "模拟响应",
                "analysis_details": {"reason": "模拟测试"}
            }

class MockFireDetectionSystem:
    """模拟火灾检测系统，用于测试"""
    
    def __init__(self, debug=False):
        self.debug = debug
        logger.info("🔄 使用模拟火灾检测系统")
    
    def check_ollama_connection(self):
        return True
    
    def detect_fire_with_ollama(self, image_path):
        """模拟火灾检测"""
        return {
            "has_fire": True,
            "confidence": 0.92,
            "description": "检测到明显的火焰和烟雾特征，可能存在火灾风险",
            "raw_response": "模拟Ollama响应：图像中包含火焰特征",
            "analysis_details": {
                "flame_detected": True,
                "smoke_detected": True,
                "intensity": "high",
                "recommendation": "请立即确认并采取相应措施"
            }
        }

# 创建服务实例
fire_service = FireDetectionService()

@app.route('/')
def index():
    """根路径，提供服务信息"""
    return jsonify({
        'service': 'Fire Detection API',
        'version': '1.0.0',
        'endpoints': {
            'health': '/api/health',
            'fire_detection_health': '/api/fire-detection/health',
            'detect_file': '/api/fire-detection/detect',
            'detect_base64': '/api/fire-detection/detect-base64',
            'list_routes': '/api/routes'
        },
        'timestamp': datetime.now().isoformat()
    })

@app.route('/api/health', methods=['GET'])
def health_check():
    """健康检查端点"""
    response = jsonify({
        'status': 'healthy',
        'message': 'Fire Detection Service is running',
        'timestamp': datetime.now().isoformat(),
        'port': 5001
    })
    return _corsify_response(response)

@app.route('/api/fire-detection/health', methods=['GET'])
def fire_detection_health():
    """火灾检测服务健康检查"""
    try:
        is_connected = fire_service.check_ollama_connection()
        
        response = jsonify({
            'status': 'healthy' if is_connected else 'degraded',
            'ollama_connected': is_connected,
            'detector_initialized': fire_service.detector is not None,
            'detector_type': 'real' if hasattr(fire_service.detector, 'check_ollama_connection') else 'mock',
            'message': '火灾检测服务运行正常' if is_connected else 'Ollama服务未连接，使用模拟模式',
            'timestamp': datetime.now().isoformat()
        })
        return _corsify_response(response)
    except Exception as e:
        logger.error(f"火灾检测健康检查失败: {str(e)}")
        response = jsonify({
            'status': 'error',
            'ollama_connected': False,
            'detector_initialized': False,
            'message': f'火灾检测服务初始化失败: {str(e)}',
            'timestamp': datetime.now().isoformat()
        })
        return _corsify_response(response), 500

@app.route('/api/fire-detection/detect', methods=['POST', 'OPTIONS'])
def detect_fire():
    """火灾检测API端点 - 文件上传"""
    if request.method == 'OPTIONS':
        return _build_cors_preflight_response()
    
    try:
        # 检查是否有文件上传
        if 'image' not in request.files:
            response = jsonify({
                'success': False,
                'message': '没有上传图片文件'
            })
            return _corsify_response(response), 400
        
        file = request.files['image']
        
        if file.filename == '':
            response = jsonify({
                'success': False,
                'message': '没有选择文件'
            })
            return _corsify_response(response), 400
        
        # 检查文件类型
        allowed_extensions = {'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp'}
        if not ('.' in file.filename and 
                file.filename.rsplit('.', 1)[1].lower() in allowed_extensions):
            response = jsonify({
                'success': False,
                'message': '不支持的文件格式，请上传图片文件'
            })
            return _corsify_response(response), 400
        
        # 保存临时文件
        temp_dir = tempfile.gettempdir()
        temp_filename = f"fire_detection_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{file.filename}"
        temp_path = os.path.join(temp_dir, temp_filename)
        
        # 使用PIL处理图片，确保兼容性
        try:
            image = Image.open(file.stream)
            # 转换为RGB格式
            if image.mode == 'RGBA':
                image = image.convert('RGB')
            elif image.mode != 'RGB':
                image = image.convert('RGB')
            
            # 保存处理后的图片
            image.save(temp_path, 'JPEG', quality=85)
            logger.info(f"临时图片已保存: {temp_path}")
            
        except Exception as e:
            logger.error(f"图片处理失败: {str(e)}")
            response = jsonify({
                'success': False,
                'message': f'图片处理失败: {str(e)}'
            })
            return _corsify_response(response), 400
        
        # 检查Ollama连接
        if not fire_service.check_ollama_connection():
            logger.warning("Ollama服务未连接，使用模拟模式")
        
        # 执行火灾检测
        logger.info("开始执行火灾检测...")
        result = fire_service.detect_fire_from_file(temp_path)
        
        # 清理临时文件
        try:
            os.remove(temp_path)
            logger.info(f"临时文件已删除: {temp_path}")
        except Exception as e:
            logger.warning(f"删除临时文件失败: {str(e)}")
        
        # 处理检测结果
        if 'error' in result:
            response = jsonify({
                'success': False,
                'message': result['error'],
                'has_fire': False,
                'confidence': 0.0
            })
            return _corsify_response(response), 500
        
        # 返回成功结果
        response_data = {
            'success': True,
            'has_fire': result.get('has_fire', False),
            'confidence': float(result.get('confidence', 0.0)),
            'description': result.get('description', ''),
            'raw_response': result.get('raw_response', ''),
            'timestamp': datetime.now().isoformat(),
            'analysis_details': result.get('analysis_details', {})
        }
        
        logger.info(f"火灾检测完成: {'检测到火灾' if response_data['has_fire'] else '未检测到火灾'}")
        response = jsonify(response_data)
        return _corsify_response(response)
        
    except Exception as e:
        logger.error(f"火灾检测过程中发生错误: {str(e)}")
        response = jsonify({
            'success': False,
            'message': f'检测过程中发生错误: {str(e)}',
            'has_fire': False,
            'confidence': 0.0
        })
        return _corsify_response(response), 500

@app.route('/api/fire-detection/detect-base64', methods=['POST', 'OPTIONS'])
def detect_fire_base64():
    """通过base64编码的图片进行火灾检测"""
    if request.method == 'OPTIONS':
        return _build_cors_preflight_response()
    
    try:
        data = request.get_json()
        
        if not data or 'image' not in data:
            response = jsonify({
                'success': False,
                'message': '请求数据格式错误，需要包含image字段（base64编码的图片）'
            })
            return _corsify_response(response), 400
        
        image_base64 = data['image']
        
        # 移除data:image前缀（如果存在）
        if ',' in image_base64:
            image_base64 = image_base64.split(',')[1]
        
        try:
            # 解码base64图片
            image_data = base64.b64decode(image_base64)
            image = Image.open(io.BytesIO(image_data))
            
            # 转换为RGB格式
            if image.mode == 'RGBA':
                image = image.convert('RGB')
            elif image.mode != 'RGB':
                image = image.convert('RGB')
            
            # 保存临时文件
            temp_dir = tempfile.gettempdir()
            temp_filename = f"fire_detection_base64_{datetime.now().strftime('%Y%m%d_%H%M%S')}.jpg"
            temp_path = os.path.join(temp_dir, temp_filename)
            image.save(temp_path, 'JPEG', quality=85)
            
            logger.info(f"Base64图片已保存为临时文件: {temp_path}")
            
        except Exception as e:
            logger.error(f"Base64图片解码失败: {str(e)}")
            response = jsonify({
                'success': False,
                'message': f'图片解码失败: {str(e)}'
            })
            return _corsify_response(response), 400
        
        # 检查Ollama连接
        if not fire_service.check_ollama_connection():
            logger.warning("Ollama服务未连接，使用模拟模式")
        
        # 执行火灾检测
        logger.info("开始执行火灾检测（Base64）...")
        result = fire_service.detect_fire_from_file(temp_path)
        
        # 清理临时文件
        try:
            os.remove(temp_path)
            logger.info(f"临时文件已删除: {temp_path}")
        except Exception as e:
            logger.warning(f"删除临时文件失败: {str(e)}")
        
        # 处理检测结果
        if 'error' in result:
            response = jsonify({
                'success': False,
                'message': result['error'],
                'has_fire': False,
                'confidence': 0.0
            })
            return _corsify_response(response), 500
        
        # 返回成功结果
        response_data = {
            'success': True,
            'has_fire': result.get('has_fire', False),
            'confidence': float(result.get('confidence', 0.0)),
            'description': result.get('description', ''),
            'raw_response': result.get('raw_response', ''),
            'timestamp': datetime.now().isoformat(),
            'analysis_details': result.get('analysis_details', {})
        }
        
        logger.info(f"火灾检测完成（Base64）: {'检测到火灾' if response_data['has_fire'] else '未检测到火灾'}")
        response = jsonify(response_data)
        return _corsify_response(response)
        
    except Exception as e:
        logger.error(f"火灾检测过程中发生错误: {str(e)}")
        response = jsonify({
            'success': False,
            'message': f'检测过程中发生错误: {str(e)}',
            'has_fire': False,
            'confidence': 0.0
        })
        return _corsify_response(response), 500

@app.route('/api/routes', methods=['GET'])
def list_routes():
    """列出所有API路由"""
    routes = []
    for rule in app.url_map.iter_rules():
        if rule.endpoint != 'static':  # 排除静态文件路由
            methods = ','.join(sorted([m for m in rule.methods if m not in ['OPTIONS', 'HEAD']]))
            routes.append({
                'endpoint': rule.endpoint,
                'methods': methods,
                'path': str(rule)
            })
    
    return _corsify_response(jsonify({'routes': sorted(routes, key=lambda x: x['path'])}))

def _build_cors_preflight_response():
    """构建CORS预检请求响应"""
    response = jsonify()
    origin = request.headers.get('Origin', 'http://localhost:3004')
    response.headers.add("Access-Control-Allow-Origin", origin)
    response.headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With, Accept")
    response.headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
    response.headers.add("Access-Control-Max-Age", "3600")
    response.headers.add("Access-Control-Allow-Credentials", "true")
    return response

if __name__ == '__main__':
    print("🔥 火灾检测服务启动")
    print("服务地址: http://localhost:5001")
    print("API文档:")
    print("  GET  /api/health - 健康检查")
    print("  GET  /api/fire-detection/health - 火灾检测服务状态")
    print("  POST /api/fire-detection/detect - 文件上传检测")
    print("  POST /api/fire-detection/detect-base64 - Base64图片检测")
    print("  GET  /api/routes - 查看所有路由")
    print("-" * 50)
    
    # 打印所有API路由
    print("已注册的API路由:")
    for rule in app.url_map.iter_rules():
        if str(rule).startswith('/api/') and rule.endpoint != 'static':
            methods = ','.join(sorted([m for m in rule.methods if m not in ['OPTIONS', 'HEAD']]))
            print(f"  {methods:<20} {str(rule)}")
    
    print("-" * 50)
    print("✅ 服务已启动，等待请求...")
    
    app.run(debug=True, host='0.0.0.0', port=5001, use_reloader=False)